#include "apricot.h"
#include "Timer.h"
#include "Window.h"
#include "Image.h"
#include "Application.h"
#include <Application.inc>

#ifdef __cplusplus
extern "C" {
#endif


#undef  my
#define inherited CWidget->
#define my  ((( PApplication) self)-> self)
#define var (( PApplication) self)

static void Application_HintTimer_handle_event( Handle, PEvent);

void
Application_init( Handle self, HV * profile)
{
   dPROFILE;
   int hintPause = pget_i( hintPause);
   Color hintColor = pget_i( hintColor), hintBackColor = pget_i( hintBackColor);
   SV * hintFont = pget_sv( hintFont);
   SV * sv;
   char * hintClass      = pget_c( hintClass);
   if ( application != nilHandle) 
      croak( "Attempt to create more than one application instance");

   CDrawable-> init( self, profile);
   list_create( &var->  widgets, 16, 16);
   list_create( &var->  modalHorizons, 0, 8);
   application = self;
   if ( !apc_application_create( self))
      croak( "Error creating application");
/* Widget init */
   SvHV_Font( pget_sv( font), &Font_buffer, "Application::init");
   my-> set_font( self, Font_buffer);
   SvHV_Font( pget_sv( popupFont), &Font_buffer, "Application::init");
   my-> set_popup_font( self, Font_buffer);
   {
      AV * av = ( AV *) SvRV( pget_sv( designScale));
      SV ** holder = av_fetch( av, 0, 0);
      if ( holder)
         var->  designScale. x = SvNV( *holder);
      else
         warn("Array panic on 'designScale'");
      holder = av_fetch( av, 1, 0);
      if ( holder)
         var->  designScale. y = SvNV( *holder);
      else
         warn("Array panic on 'designScale'");
      pdelete( designScale);
   }
   var->  text = newSVpv("", 0);
   opt_set( optModalHorizon);

   /* store extra info */
   {
      HV * hv = ( HV *) SvRV( var-> mate);
      (void) hv_store( hv, "PrinterClass",  12, newSVpv( pget_c( printerClass),  0), 0);
      (void) hv_store( hv, "PrinterModule", 13, newSVpv( pget_c( printerModule), 0), 0);
      (void) hv_store( hv, "HelpClass",     9,  newSVpv( pget_c( helpClass),     0), 0);
      (void) hv_store( hv, "HelpModule",    10, newSVpv( pget_c( helpModule),    0), 0);
   }

   {
      HV * profile = newHV();
      static Timer_vmt HintTimerVmt;

      pset_H( owner, self);
      pset_i( timeout, hintPause);
      pset_c( name, "HintTimer");
      var->  hintTimer = create_instance( "Prima::Timer");
      protect_object( var-> hintTimer);
      hv_clear( profile);
      memcpy( &HintTimerVmt, CTimer, sizeof( HintTimerVmt));
      HintTimerVmt. handle_event = Application_HintTimer_handle_event;
      (( PTimer) var->  hintTimer)-> self = &HintTimerVmt;

      pset_H( owner, self);
      pset_i( color, hintColor);
      pset_i( backColor, hintBackColor);
      pset_i( visible, 0);
      pset_i( selectable, 0);
      pset_i( showHint, 0);
      pset_c( name, "HintWidget");
      pset_sv( font, hintFont);
      var->  hintWidget = create_instance( hintClass);
      protect_object( var->  hintWidget);
      sv_free(( SV *) profile);
   }

   if ( SvTYPE( sv = pget_sv( accelItems)) != SVt_NULL)
      my-> set_accelItems( self, sv);
   if ( SvTYPE( sv = pget_sv( popupItems)) != SVt_NULL)
      my-> set_popupItems( self, sv);
   pdelete( accelTable);
   pdelete( accelItems);
   pdelete( popupItems);

   my-> set( self, profile);
   CORE_INIT_TRANSIENT(Application);
}

void
Application_done( Handle self)
{
   if ( self != application) return;
   unprotect_object( var-> hintTimer);
   unprotect_object( var-> hintWidget);
   list_destroy( &var->  modalHorizons);
   list_destroy( &var->  widgets);
   if ( var-> text ) SvREFCNT_dec( var-> text);
   if ( var-> hint ) SvREFCNT_dec( var-> hint);
   free( var-> helpContext);
   var-> accelTable = var-> hintWidget = var-> hintTimer = nilHandle;
   var-> helpContext = nil;
   var-> hint = var-> text = nil;
   apc_application_destroy( self);
   CDrawable-> done( self);
   application = nilHandle;
}

void
Application_cleanup( Handle self)
{
   int i;

   for ( i = 0; i < var-> widgets. count; i++)
      Object_destroy( var-> widgets. items[i]);
      
   if ( var-> icon)
      my-> detach( self, var-> icon, true);
   var-> icon = nilHandle;

   my-> first_that_component( self, (void*)kill_all, nil);

   CDrawable-> cleanup( self);
}


void
Application_set( Handle self, HV * profile)
{
   pdelete( bottom);
   pdelete( buffered);
   pdelete( capture);
   pdelete( centered);
   pdelete( clipOwner);
   pdelete( enabled);
   pdelete( focused);
   pdelete( geometry);
   pdelete( geomHeight);
   pdelete( geomSize);
   pdelete( geomWidth);
   pdelete( growMode);
   pdelete( height);
   pdelete( hintClass);
   pdelete( hintVisible);
   pdelete( layered);
   pdelete( left);
   pdelete( modalHorizon);
   pdelete( origin);
   pdelete( owner);
   pdelete( ownerBackColor);
   pdelete( ownerColor);
   pdelete( ownerFont);
   pdelete( ownerPalette);
   pdelete( ownerShowHint);
   pdelete( palette);
   pdelete( pack);
   pdelete( place);
   pdelete( printerClass);
   pdelete( printerModule);
   pdelete( helpClass);
   pdelete( helpModule);
   pdelete( rect);
   pdelete( rigth);
   pdelete( selectable);
   pdelete( shape);
   pdelete( size);
   pdelete( syncPaint);
   pdelete( tabOrder);
   pdelete( tabStop);
   pdelete( transparent);
   pdelete( text);
   pdelete( top);
   pdelete( visible);
   pdelete( width);
   inherited set( self, profile);
}

void Application_handle_event( Handle self, PEvent event)
{
   switch ( event-> cmd)
   {
      case cmPost:
      if ( event-> gen. H != self)
      {
         ((( PComponent) event-> gen. H)-> self)-> message( event-> gen. H, event);
         event-> cmd = 0;
         if ( var->  stage > csNormal) return;
      }
      break;
   }
   inherited handle_event ( self, event);
}

void
Application_sync( char * dummy)
{
   apc_application_sync();
}

void
Application_yield( char * dummy)
{
   apc_application_yield();
}

Bool
Application_begin_paint( Handle self)
{
   Bool ok;
   if ( !CDrawable-> begin_paint( self))
      return false;
   if ( !( ok = apc_application_begin_paint( self))) {
      CDrawable-> end_paint( self);
      perl_error();
   }
   return ok;
}

Bool
Application_begin_paint_info( Handle self)
{
   Bool ok;
   if ( is_opt( optInDraw))     return true;
   if ( !CDrawable-> begin_paint_info( self))
      return false;
   if ( !( ok = apc_application_begin_paint_info( self))) {
      CDrawable-> end_paint_info( self);
      perl_error();
   }
   return ok;
}

void
Application_detach( Handle self, Handle objectHandle, Bool kill)
{
   inherited detach( self, objectHandle, kill);
   if ( var->  autoClose &&
        ( var->  widgets. count == 1) &&
        kind_of( objectHandle, CWidget) &&
        ( objectHandle != var->  hintWidget)
       ) my-> close( self);
}

void
Application_end_paint( Handle self)
{
   if ( !is_opt( optInDraw)) return;
   apc_application_end_paint( self);
   CDrawable-> end_paint( self);
}

void
Application_end_paint_info( Handle self)
{
   if ( !is_opt( optInDrawInfo)) return;
   apc_application_end_paint_info( self);
   CDrawable-> end_paint_info( self);
}

Bool
Application_focused( Handle self, Bool set, Bool focused)
{
   if ( set) return false;
   return inherited focused( self, set, focused);
}

void Application_bring_to_front( Handle self) {}
void Application_show( Handle self) {}
void Application_hide( Handle self) {}
void Application_insert_behind( Handle self, Handle view) {}
void Application_send_to_back( Handle self) {}

SV*
Application_fonts( Handle self, char * name, char * encoding)
{
   int count, i;
   AV * glo = newAV();
   PFont fmtx = apc_fonts( self, name[0] ? name : nil,
      encoding[0] ? encoding : nil, &count);
   for ( i = 0; i < count; i++) {
      SV * sv      = sv_Font2HV( &fmtx[ i]);
      HV * profile = ( HV*) SvRV( sv);
      if ( fmtx[i]. utf8_flags & FONT_UTF8_NAME) {
         SV ** entry = hv_fetch(( HV*) SvRV( sv), "name", 4, 0);
	 if ( entry && SvOK( *entry))
            SvUTF8_on( *entry);
      }	 
      if ( fmtx[i]. utf8_flags & FONT_UTF8_FAMILY) {
         SV ** entry = hv_fetch(( HV*) SvRV( sv), "family", 6, 0);
	 if ( name && SvOK( *entry))
            SvUTF8_on( *entry);
      }	 
      if ( fmtx[i]. utf8_flags & FONT_UTF8_ENCODING) {
         SV ** entry = hv_fetch(( HV*) SvRV( sv), "encoding", 8, 0);
	 if ( name && SvOK( *entry))
            SvUTF8_on( *entry);
      }	 
      if ( name[0] == 0 && encoding[0] == 0) {
         /* Read specially-coded (const char*) encodings[] vector,
            stored in fmtx[i].encoding. First pointer is filled with 0s,
            except the last byte which is a counter. Such scheme
            allows max 31 encodings per entry to be coded with sizeof(char*)==8.
            The interface must be re-implemented, but this requires
            either change in gencls syntax so arrays can be members of hashes,
            or passing of a dynamic-allocated pointer vector here.
          */
         char ** enc = (char**) fmtx[i].encoding;
         unsigned char * shift = (unsigned char*) enc + sizeof(char *) - 1, j = *shift;
         AV * loc = newAV();
         pset_sv_noinc( encoding, newSVpv(( j > 0) ? *(++enc) : "", 0));
         while ( j--) av_push( loc, newSVpv(*(enc++),0));
         pset_sv_noinc( encodings, newRV_noinc(( SV*) loc));
      }
      pdelete( resolution);
      pdelete( codepage);
      av_push( glo, sv);
   }
   free( fmtx);
   return newRV_noinc(( SV *) glo);
}

SV*
Application_font_encodings( Handle self, char * encoding)
{
   AV * glo = newAV();
   HE *he;
   PHash h = apc_font_encodings( self);

   if ( !h) return newRV_noinc(( SV *) glo);
   hv_iterinit(( HV*) h);
   for (;;)
   {
      void *value, *key;
      STRLEN  keyLen;
      if (( he = hv_iternext( h)) == nil)
         break;
      value  = HeVAL( he);
      key    = HeKEY( he);
      keyLen = HeKLEN( he);
      av_push( glo, newSVpvn(( char*) key, keyLen));
   }
   return newRV_noinc(( SV *) glo);
}

Font
Application_get_default_font( char * dummy)
{
   Font font;
   apc_font_default( &font);
   return font;
}

Font
Application_get_message_font( char * dummy)
{
   Font font;
   apc_sys_get_msg_font( &font);
   return font;
}

Font
Application_get_caption_font( char * dummy)
{
   Font font;
   apc_sys_get_caption_font( &font);
   return font;
}


int
Application_get_default_cursor_width( char * dummy)
{
   return apc_sys_get_value( svXCursor);
}

Point
Application_get_default_scrollbar_metrics( char * dummy)
{
   Point ret;
   ret. x = apc_sys_get_value( svXScrollbar);
   ret. y = apc_sys_get_value( svYScrollbar);
   return ret;
}

Point
Application_get_default_window_borders( char * dummy, int borderStyle)
{
   Point ret = { 0,0};
   switch ( borderStyle) {
   case bsNone:
      ret.x = svXbsNone;
      ret.y = svYbsNone;
      break;
   case bsSizeable:
      ret.x = svXbsSizeable;
      ret.y = svYbsSizeable;
      break;
   case bsSingle:
      ret.x = svXbsSingle;
      ret.y = svYbsSingle;
      break;
   case bsDialog:
      ret.x = svXbsDialog;
      ret.y = svYbsDialog;
      break;
   default:
      return ret;
   }
   ret. x = apc_sys_get_value( ret. x);
   ret. y = apc_sys_get_value( ret. y);
   return ret;
}

int
Application_get_system_value( char * dummy, int sysValue)
{
   return apc_sys_get_value( sysValue);
}

SV *
Application_get_system_info( char * dummy)
{
   HV * profile = newHV();
   char system   [ 1024];
   char release  [ 1024];
   char vendor   [ 1024];
   char arch     [ 1024];
   char gui_desc [ 1024];
   int  os, gui;

   os  = apc_application_get_os_info( system, sizeof( system),
                                      release, sizeof( release),
                                      vendor, sizeof( vendor),
                                      arch, sizeof( arch));
   gui = apc_application_get_gui_info( gui_desc, sizeof( gui_desc));

   pset_i( apc,            os);
   pset_i( gui,            gui);
   pset_c( system,         system);
   pset_c( release,        release);
   pset_c( vendor,         vendor);
   pset_c( architecture,   arch);
   pset_c( guiDescription, gui_desc);

   return newRV_noinc(( SV *) profile);
}

Handle
Application_get_widget_from_handle( Handle self, SV * handle)
{
   ApiHandle apiHandle;
   if ( SvIOK( handle))
           apiHandle = SvUVX( handle);
   else
      apiHandle = sv_2uv( handle);
   return apc_application_get_handle( self, apiHandle);
}

Handle
Application_get_hint_widget( Handle self)
{
   return var->  hintWidget;
}

static Bool
icon_notify ( Handle self, Handle child, Handle icon)
{
    if ( kind_of( child, CWindow) && (( PWidget) child)-> options. optOwnerIcon) {
       CWindow( child)-> set_icon( child, icon);
       PWindow( child)-> options. optOwnerIcon = 1;
    }
    return false;
}

Handle
Application_icon( Handle self, Bool set, Handle icon)
{
   if ( var-> stage > csFrozen) return nilHandle;

   if ( !set)
      return var-> icon;

   if ( icon && !kind_of( icon, CImage)) {
       warn("Illegal object reference passed to Application::icon");
       return nilHandle;
   }
   if ( icon) {
      icon = ((( PImage) icon)-> self)-> dup( icon);
      ++SvREFCNT( SvRV((( PAnyObject) icon)-> mate));
   }
   my-> first_that( self, (void*)icon_notify, (void*)icon);
   if ( var-> icon)
      my-> detach( self, var-> icon, true);
   var-> icon = icon;
   if ( icon && ( list_index_of( var-> components, icon) < 0))
      my-> attach( self, icon);
   return nilHandle;
}

Handle
Application_get_focused_widget( Handle self)
{
   return apc_widget_get_focused();
}

Handle
Application_get_active_window( Handle self)
{
   return apc_window_get_active();
}

Bool
Application_autoClose( Handle self, Bool set, Bool autoClose)
{
   if ( !set)
      return var->  autoClose;
   return var-> autoClose = autoClose;
}

SV *
Application_sys_action( char * dummy, char * params)
{
   char * i = apc_system_action( params);
   SV * ret = i ? newSVpv( i, 0) : nilSV;
   free( i);
   return ret;
}

typedef struct _SingleColor
{
   Color color;
   int   index;
} SingleColor, *PSingleColor;


Color
Application_colorIndex( Handle self, Bool set, int index, Color color)
{
   if ( var->  stage > csFrozen) return clInvalid;
   if (( index < 0) || ( index > ciMaxId)) return clInvalid;
   if ( !set) {
      switch ( index) {
        case ciFore:
           return opt_InPaint ?
              CDrawable-> get_color ( self) : var-> colors[ index];
        case ciBack:
           return opt_InPaint ?
              CDrawable-> get_backColor ( self) : var-> colors[ index];
        default:
           return  var->  colors[ index];
      }
   } else {
      SingleColor s;
      s. color = color;
      s. index = index;
      if ( !opt_InPaint) my-> first_that( self, (void*)single_color_notify, &s);
      if ( opt_InPaint) switch ( index) {
         case ciFore:
            CDrawable-> set_color ( self, color);
            break;
         case ciBack:
            CDrawable-> set_backColor ( self, color);
            break;
       }
       var-> colors[ index] = color;
   }
   return clInvalid;
}

void
Application_set_font( Handle self, Font font)
{
   if ( !opt_InPaint) my-> first_that( self, (void*)font_notify, &font);
   apc_font_pick( self, &font, & var-> font);
   if ( opt_InPaint) apc_gp_set_font ( self, &var-> font);
}


Bool
Application_close( Handle self)
{
   if ( var->  stage > csNormal) return true;
   return my-> can_close( self) ? ( apc_application_close( self), true) : false;
}

Bool
Application_insertMode( Handle self, Bool set, Bool insMode)
{
   if ( !set)
      return apc_sys_get_insert_mode();
   return apc_sys_set_insert_mode( insMode);
}


Handle 
Application_get_modal_window( Handle self, int modalFlag, Bool topMost)
{
   if ( modalFlag == mtExclusive) {
      return topMost ? var-> topExclModal   : var-> exclModal;
   } else if ( modalFlag == mtShared) {
      return topMost ? var-> topSharedModal : var-> sharedModal;
   } 
   return nilHandle;
}

SV * 
Application_get_monitor_rects( Handle self)
{
   int i, nrects;
   Rect2 * rects = apc_application_get_monitor_rects(self, &nrects);
   AV * ret = newAV();
   for ( i = 0; i < nrects; i++) {
   	AV * rect = newAV();
	av_push( rect, newSViv( rects[i].x));
	av_push( rect, newSViv( rects[i].y));
	av_push( rect, newSViv( rects[i].width));
	av_push( rect, newSViv( rects[i].height));
	av_push( ret, newRV_noinc(( SV *) rect));
   }
   free(rects);

   /* .. or return at least the current size */
   if ( nrects == 0) {
   	AV * rect = newAV();
	Point sz = apc_application_get_size(self);
	av_push( rect, newSViv( 0));
	av_push( rect, newSViv( 0));
	av_push( rect, newSViv( sz.x));
	av_push( rect, newSViv( sz.y));
	av_push( ret, newRV_noinc(( SV *) rect));
   }

   return newRV_noinc(( SV *) ret);
}


Handle
Application_get_parent( Handle self)
{
   return nilHandle;
}

Point
Application_get_scroll_rate( Handle self)
{
   Point ret;
   ret. x = apc_sys_get_value( svAutoScrollFirst);
   ret. y = apc_sys_get_value( svAutoScrollNext);
   return ret;
}

static void hshow( Handle self)
{
   PWidget_vmt hintUnder = CWidget( var->  hintUnder);
   SV * text = hintUnder-> get_hint( var->  hintUnder);
   Point size  = hintUnder-> get_size( var->  hintUnder);
   Point s = my-> get_size( self);
   Point fin = {0,0};
   Point pos = fin;
   Point mouse = my-> get_pointerPos( self);
   Point hintSize;
   PWidget_vmt hintWidget = CWidget( var->  hintWidget);

   apc_widget_map_points( var-> hintUnder, true, 1, &pos);

   hintWidget-> set_text( var->  hintWidget, text);
   hintSize = hintWidget-> get_size( var->  hintWidget);

   fin. x = mouse. x - 16;
   fin. y = pos. y - hintSize. y - 1;
   if ( fin. y > mouse. y - hintSize. y - 32) fin. y = mouse. y - hintSize. y - 32;

   if ( fin. x + hintSize. x >= s. x) fin. x = pos. x - hintSize. x;
   if ( fin. x < 0) fin. x = 0;
   if ( fin. y + hintSize. y >= s. y) fin. y = pos. y - hintSize. y;
   if ( fin. y < 0) fin. y = pos. y + size. y + 1;
   if ( fin. y < 0) fin. y = 0;

   hintWidget-> set_origin( var->  hintWidget, fin);
   hintWidget-> show( var->  hintWidget);
   hintWidget-> bring_to_front( var->  hintWidget);
}

void
Application_HintTimer_handle_event( Handle timer, PEvent event)
{
   CComponent-> handle_event( timer, event);
   if ( event-> cmd == cmTimer) {
      Handle self = application;
      CTimer(timer)-> stop( timer);
      if ( var->  hintActive == 1) {
         Event ev = {cmHint};
         if (   !var->hintUnder
             || apc_application_get_widget_from_point( self,
                   my-> get_pointerPos(self)) != var->hintUnder
             || PObject( var-> hintUnder)-> stage != csNormal)
            return;
         ev. gen. B = true;
         ev. gen. H = var->  hintUnder;
         var->  hintVisible = 1;
         if (( PWidget( var->  hintUnder)-> stage == csNormal) &&
             ( CWidget( var->  hintUnder)-> message( var->  hintUnder, &ev)))
             hshow( self);
      } else if ( var->  hintActive == -1)
         var->  hintActive = 0;
   }
}

void
Application_set_hint_action( Handle self, Handle view, Bool show, Bool byMouse)
{
   if ( var-> stage >= csFrozen) return;
   if ( show && !is_opt( optShowHint)) return;
   if ( show)
   {
      var->  hintUnder = view;
      if ( var->  hintActive == -1)
      {
         Event ev = {cmHint};
         ev. gen. B = true;
         ev. gen. H = view;
         ((( PTimer) var->  hintTimer)-> self)-> stop( var-> hintTimer);
         var->  hintVisible = 1;
         if (( PWidget( view)-> stage == csNormal) &&
             ( CWidget( view)-> message( view, &ev)))
             hshow( self);
      } else {
         if ( !byMouse && var->  hintActive == 1) return;
         CTimer( var->  hintTimer)-> start( var-> hintTimer);
      }
      var->  hintActive = 1;
   } else {
      int oldHA = var->  hintActive;
      int oldHV = var->  hintVisible;
      if ( oldHA != -1)
         ((( PTimer) var-> hintTimer)-> self)-> stop( var-> hintTimer);
      if ( var->  hintVisible)
      {
         Event ev = {cmHint};
         ev. gen. B = false;
         ev. gen. H = view;
         var->  hintVisible = 0;
         if (( PWidget( view)-> stage != csNormal) ||
              ( CWidget( view)-> message( view, &ev)))
            CWidget( var->  hintWidget)-> hide( var->  hintWidget);
      }
      if ( oldHA != -1) var->  hintActive = 0;
      if ( byMouse && oldHV) {
         var->  hintActive = -1;
         CTimer( var->  hintTimer)-> start( var->  hintTimer);
      }
   }
}

Color
Application_hintColor( Handle self, Bool set, Color hintColor)
{
   if ( !set)
      return CWidget( var-> hintWidget)-> get_color( var->  hintWidget);
   return CWidget( var->  hintWidget)-> set_color( var->  hintWidget, hintColor);
}

Color
Application_hintBackColor( Handle self, Bool set, Color hintBackColor)
{
   if ( !set)
      return CWidget( var->  hintWidget)-> get_backColor( var-> hintWidget);
   return CWidget( var->  hintWidget)-> set_backColor( var->  hintWidget, hintBackColor);
}

int
Application_hintPause( Handle self, Bool set, int hintPause)
{
   if ( !set)
      return CTimer( var->  hintTimer)-> get_timeout( var->  hintTimer);
   return CTimer( var->  hintTimer)-> set_timeout( var->  hintTimer, hintPause);
}

void
Application_set_hint_font( Handle self, Font hintFont)
{
   CWidget( var-> hintWidget)-> set_font( var->  hintWidget, hintFont);
}


Font
Application_get_hint_font( Handle self)
{
   return CWidget( var->  hintWidget)-> get_font( var->  hintWidget);
}

Bool
Application_showHint( Handle self, Bool set, Bool showHint)
{
   if ( !set)
      return inherited showHint( self, set, showHint);
   opt_assign( optShowHint, showHint);
   return false;
}

Handle Application_next( Handle self) { return self;}
Handle Application_prev( Handle self) { return self;}

Bool
Application_layered( Handle self, Bool set, Bool layered)
{
   return false;
}

SV *
Application_palette( Handle self, Bool set, SV * palette)
{
   return CDrawable-> palette( self, set, palette);
}

Handle
Application_top_frame( Handle self, Handle from)
{
   while ( from) {
      if ( kind_of( from, CWindow) &&
             (( PWidget( from)-> owner == application) || !CWidget( from)-> get_clipOwner(from))
         )
         return from;
      from = PWidget( from)-> owner;
   }
   return application;
}

Handle
Application_get_image( Handle self, int x, int y, int xLen, int yLen)
{
   HV * profile;
   Handle i;
   Bool ret;
   Point sz;
   if ( var->  stage > csFrozen) return nilHandle;
   if ( x < 0 || y < 0 || xLen <= 0 || yLen <= 0) return nilHandle;
   sz = apc_application_get_size( self);
   if ( x + xLen > sz. x) xLen = sz. x - x;
   if ( y + yLen > sz. y) yLen = sz. y - y;
   if ( x >= sz. x || y >= sz. y || xLen <= 0 || yLen <= 0) return nilHandle;

   profile = newHV();
   i = Object_create( "Prima::Image", profile);
   sv_free(( SV *) profile);
   ret = apc_application_get_bitmap( self, i, x, y, xLen, yLen);
   --SvREFCNT( SvRV((( PAnyObject) i)-> mate));
   return ret ? i : nilHandle;
}

/*
 * Cannot return nilHandle.
 */
Handle
Application_map_focus( Handle self, Handle from)
{
   Handle topFrame = my-> top_frame( self, from);
   Handle topShared;

   if ( var->  topExclModal)
      return ( topFrame == var->  topExclModal) ? from : var->  topExclModal;

   if ( !var->  topSharedModal && var->  modalHorizons. count == 0)
      return from; /* return from if no shared modals active */

  if ( topFrame == self) {
      if ( !var->  topSharedModal) return from;
      topShared = var->  topSharedModal;
   } else {
      Handle horizon =
         ( !CWindow( topFrame)-> get_modalHorizon( topFrame)) ?
         CWindow( topFrame)-> get_horizon( topFrame) : topFrame;
      if ( horizon == self)
         topShared = var->  topSharedModal;
      else
         topShared = PWindow( horizon)-> topSharedModal;
   }

   return ( !topShared || ( topShared == topFrame)) ? from : topShared;
}

static Handle
popup_win( Handle xTop)
{
   PWindow_vmt top = CWindow( xTop);
   if ( !top-> get_visible( xTop))
      top-> set_visible( xTop, 1);
   if ( top-> get_windowState( xTop) == wsMinimized)
      top-> set_windowState( xTop, wsNormal);
   top-> set_selected( xTop, 1);
   return xTop;
}

Handle
Application_popup_modal( Handle self)
{
   Handle ha = apc_window_get_active();
   Handle xTop;

   if ( var->  topExclModal) {
   /* checking exclusive modal chain */
      xTop = ( !ha || ( PWindow(ha)->modal == 0)) ? var->  exclModal : ha;
      while ( xTop) {
         if ( PWindow(xTop)-> nextExclModal) {
            CWindow(xTop)-> bring_to_front( xTop);
            xTop = PWindow(xTop)-> nextExclModal;
         } else {
            return popup_win( xTop);
         }
      }
   } else {
      if ( !var->  topSharedModal && var->  modalHorizons. count == 0)
         return nilHandle; /* return from if no shared modals active */
      /* checking shared modal chains */
      if ( ha) {
         xTop = ( PWindow(ha)->modal == 0) ? CWindow(ha)->get_horizon(ha) : ha;
         if ( xTop == application) xTop = var->  sharedModal;
      } else
         xTop = var->  sharedModal ? var->  sharedModal : var->  modalHorizons. items[ 0];

      while ( xTop) {
         if ( PWindow(xTop)-> nextSharedModal) {
            CWindow(xTop)-> bring_to_front( xTop);
            xTop = PWindow(xTop)-> nextSharedModal;
         } else {
            return popup_win( xTop);
         }
      }
   }

   return nilHandle;
}

Bool
Application_pointerVisible( Handle self, Bool set, Bool pointerVisible)
{
   if ( !set)
      return apc_pointer_get_visible( self);
   return apc_pointer_set_visible( self, pointerVisible);
}

Point
Application_size( Handle self, Bool set, Point size)
{
   if ( set) return size;
   return apc_application_get_size( self);
}

Point
Application_origin( Handle self, Bool set, Point origin)
{
   Point p = { 0, 0};
   return p;
}

Bool
Application_modalHorizon( Handle self, Bool set, Bool modalHorizon)
{
   return true;
}

Bool
Application_wantUnicodeInput( Handle self, Bool set, Bool want_ui)
{
   if ( !set) return var-> wantUnicodeInput;
   if ( apc_sys_get_value( svCanUTF8_Input)) 
      var-> wantUnicodeInput = want_ui;
   return 0;
}


void   Application_update_sys_handle( Handle self, HV * profile) {}
Bool   Application_get_capture( Handle self) { return false; }
Bool   Application_set_capture( Handle self, Bool capture, Handle confineTo) { return false; }
void   Application_set_centered( Handle self, Bool x, Bool y) {}

Bool   Application_tabStop( Handle self, Bool set, Bool tabStop)       { return false; }
Bool   Application_selectable( Handle self, Bool set, Bool selectable) { return false; }
Handle Application_shape( Handle self, Bool set, Handle mask)          { return nilHandle; }
Bool   Application_syncPaint( Handle self, Bool set, Bool syncPaint)   { return false; }
Bool   Application_visible( Handle self, Bool set, Bool visible)       { return true; }
Bool   Application_buffered( Handle self, Bool set, Bool buffered)     { return false; }
Bool   Application_enabled( Handle self, Bool set, Bool enable)        { return true;}
int    Application_growMode( Handle self, Bool set, int flags)         { return 0; }
Bool   Application_hintVisible( Handle self, Bool set, Bool visible)   { return false; }
Handle Application_owner( Handle self, Bool set, Handle owner)         { return nilHandle; }
Bool   Application_ownerColor( Handle self, Bool set, Bool ownerColor) { return false; }
Bool   Application_ownerBackColor( Handle self, Bool set, Bool ownerBackColor) { return false; }
Bool   Application_ownerFont( Handle self, Bool set, Bool ownerFont)   { return false; }
Bool   Application_ownerShowHint( Handle self, Bool set, Bool ownerShowHint) { return false; }
Bool   Application_ownerPalette( Handle self, Bool set, Bool ownerPalette) { return false; }
Bool   Application_clipOwner( Handle self, Bool set, Bool clipOwner)   { return true; }
int    Application_tabOrder( Handle self, Bool set, int tabOrder)      { return 0; }
SV   * Application_text    ( Handle self, Bool set, SV * text)       { return nilSV; }
Bool   Application_transparent( Handle self, Bool set, Bool transparent) { return false; }
Bool   Application_validate_owner( Handle self, Handle * owner, HV * profile) { *owner = nilHandle; return true; }

#ifdef __cplusplus
}
#endif
